package example.annotation.processor;

import example.annotation.Compile;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;

@SupportedSourceVersion(SourceVersion.RELEASE_11)
@SupportedAnnotationTypes("example.annotation.Compile")
public class CompileProcessor extends AbstractProcessor {

    public static final String compiledClassSuffix = "_Compile";

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        logInfo("processing the Compile annotation");
        if (roundEnv.processingOver() || annotations.isEmpty()) {
            return false;
        }

        Set<? extends Element> needCompile = roundEnv.getElementsAnnotatedWith(Compile.class);
        for (Element c: needCompile) {
            String compiledClassName = c.toString() + compiledClassSuffix;
            try {
                JavaFileObject compiledFile = processingEnv.getFiler().createSourceFile(compiledClassName, c);
                try (Writer writer = compiledFile.openWriter()) {
                    logInfo("processing the Compile annotation on Element: " + c.toString());
                    writeCode(writer, (TypeElement) c);
                } catch (IOException e) {
                    logError("Failed saving compiled file " + compiledClassName);
                }
            } catch (IOException e) {
                logError("Failed creating compiled file " + compiledClassName);
            }
        }
        return false;
    }

    private void writeCode(Writer writer, TypeElement c) throws IOException {
        String orinalClassName = c.getQualifiedName().toString();
        int lastDotIndex = orinalClassName.lastIndexOf(".");
        CharSequence packageName = orinalClassName.subSequence(0, lastDotIndex);
        CharSequence simpleName = orinalClassName.subSequence(lastDotIndex + 1, orinalClassName.length());
        writer.append("package ")
                .append(String.valueOf(packageName))
                .append(";\n");
        writer.append("public class ").append(String.valueOf(simpleName)).append(compiledClassSuffix).append(" {\n");
        writer.append("\tpublic String toString() { return \"from Compiled\"; }");
        writer.append("}\n");

    }

    private void logInfo(String message) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
    }
    private void logError(String message) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
    }


}
